package com.yunchang.spring.visitor.core.handler.request;

import com.yunchang.spring.visitor.core.constant.ContentType;
import com.yunchang.spring.visitor.core.utils.StreamUtil;
import com.yunchang.spring.visitor.core.utils.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * <pre>
 * IRequestHandler的基类，提供了获取Request入参和InputStream流内容的基础实现。
 * 如果项目需要支持application/json或application/xml等类型的请求，
 * 则子类需要实现{@link IRequestHandler#parseToMap(String, ContentType)}接口，将InputStream流内容转为map。
 * </pre>
 * Created by jasontujun on 2019/2/15.
 */
public abstract class ABaseRequestHandler implements IRequestHandler {

    private static final Logger logger = LoggerFactory.getLogger(ABaseRequestHandler.class);

    protected static final String httpContentKey = "InputStreamData";

    // 通过ThreadLocal变量，缓存InputStream流的内容
    protected class CacheContent {
        int requestHashCode;
        String content;

        public CacheContent(int requestHashCode, String content) {
            this.requestHashCode = requestHashCode;
            this.content = content;
        }
    }

    protected ThreadLocal<CacheContent> cacheContent = new ThreadLocal<CacheContent>();

    @Override
    public Map<String, String> getParams(HttpServletRequest request) {
        return WebUtil.getParamMapByRequest(request);
    }

    @Override
    public String getHttpContent(HttpServletRequest request) {
        // 由于InputStream流只能读取一次，不能反复读取，因此会将流的数据缓存进Request中
        // 如果已经解析过InputStream流，直接返回缓存的数据
        if (cacheContent.get() != null && request.hashCode() == cacheContent.get().requestHashCode) {
            return cacheContent.get().content;
        }
        // 否则，解析InputStream流，并将解析的数据缓存进Request中，再返回
        try {
            String httpContent = StreamUtil.copyToString(request.getInputStream());
            cacheContent.set(new CacheContent(request.hashCode(), httpContent));
            return httpContent;
        } catch (Exception e) {
            logger.error("", e);
            return null;
        }
    }
}
